Unauthenticated Root Access to the Enphase IQ Gateway | j027Table of ContentsMotivation<br>Finding the Vulnerabilities<br>Escalating Privileges<br>SD Card Bind Mounts<br>Firewall Rules<br>The Disclosure<br>The Patch Rollout<br>Download Links<br>Published Advisories
Motivation#<br>One day, my IQ Gateway stopped working.<br>The IQ Gateway is a device from Enphase designed to collect solar panel production data, and optionally consumption data,<br>and then report it to the cloud. It also provides per-panel data from each microinverter.<br>Since I was busy, I didn’t get to check on it immediately.<br>When I eventually took a look, I noticed the device on the network, but the local API was non-functional.<br>I also noticed that the device showed as offline in the mobile app.<br>When I looked at the device, I saw all four lights flashing red.<br>I tried a reboot, but that didn’t help.<br>I contacted Enphase support, which eventually led to an RMA to replace the old unit.<br>It was challenging to gain installer-level access, but I eventually got it.<br>This was necessary to let me swap out the Gateway myself without needing to call support.<br>I also was interested in understanding why this failure occurred, and thought this level of access might help.<br>After gaining access, I requested a reboot on my own system.<br>I didn’t think it would do anything, but the system started reporting data the next morning.<br>However, all past data during the time that the gateway wasn’t reporting to the cloud was lost.<br>I set up some uptime monitoring, and while the device worked, it would randomly go down for an hour or two, usually at night.<br>As the device deteriorated, it started dropping out during the daytime, as well as exhibiting other odd behaviors.<br>This degradation pushed me to finally replace the failing IQ Gateway with the RMA unit, which fixed all the stability issues I had.<br>However, I wanted to understand the root cause so that my new unit doesn’t fail in the same way.<br>To investigate, I followed the instructions in the comments of this blog post to gain root access.<br>I first began by attempting to dump the currently-installed firmware.<br>I had previously obtained encrypted firmware images from the installer toolkit mobile app,<br>so I was in search of the “eecrypt” binary mentioned by another researcher to decrypt them.<br>I eventually got what I needed by piping the files through tar over netcat with a speed limit to avoid overloading the hardware.<br>I also look at the Embedded Multi-Media Card (EMMC) health and quickly discover it is past its lifespan because of excessive writes.<br>In fact, it had 8,000 P/E cycles on a 4GB EMMC, which equates to roughly 32 Terabytes Written (TBW).<br>I first start looking into replacing the EMMC chip, but I notice that there isn’t any higher-endurance EMMC chip that would fit.<br>I then realize the device has a USB port. I could use this as storage and bind mount the files with heavy writes.<br>Finding the Vulnerabilities#<br>I didn’t want to reinstall the RMA unit just so I could root it, so I decide to search for security vulnerabilities.<br>I feel that it is very likely for this device to have a vulnerability that gives me root, since IoT devices have notoriously bad security.<br>My RMA unit had shipped with an older firmware with known vulnerabilities, which I initially was aiming to discover.<br>It was more difficult to do this than I had expected, which led me to analyzing the latest firmware instead.<br>Running the “eecrypt” binary under QEMU, I was able to decrypt the latest firmware images I had extracted from the installer app earlier.<br>Because of the large number of components in the firmware, I decide to use Claude Opus 4.6 through Github Copilot to search for vulnerabilities for me.<br>I ask it to create a report of potential vulnerabilities for me to review.<br>One of the first things that the agent noticed, which it regarded as critical, was a command injection vulnerability in the authentication handler.<br>The vulnerable code is as follows:<br>-- Calculate the SHA-512 digest of the decoded API key<br>local digest_cmd = "echo -n '" .. api_key .. "' | openssl dgst -sha512 | awk '{ print $NF }'"<br>local calculated_digest = io.popen(digest_cmd):read("*a")
This code is vulnerable because it takes an api key that originates from user input and directly places it into a shell command.<br>Because of this behavior, crafted input from an unauthenticated user can be used to execute arbitrary commands.<br>Since the web server runs as the “nobody” user and the authentication handler runs inside of it, everything that runs as a child process also runs as the same user.<br>As a result, this command injection only allows you to execute commands as the “nobody” user, while the mongrel2 web server runs ruby as root for the backend.<br>I ask Opus to explain to me how different parts of the firmware work, such as the firmware updates, SSH configuration, and other parts of the firmware I’m interested in. This helps me to...