Pushing WebKit's Buttons with a Mobile Pwn2Own Exploit

February 12, 2018 | Jasiel Spelman

With Pwn2Own 2018 a little over a month away, and Mobile Pwn2Own 2017 now in the rear-view mirror, it’s a great time to talk about one of the bugs used during the contest.

During the last Mobile Pwn2Own (MP2O), one of the many bugs we saw was a use-after-free in Safari. To exploit this bug, an attacker just needs to convince someone to browse to a malicious website from an affected iPhone. The team from 360 Security demonstrated this bug during the last MP2O and earned themselves $20,000 in the process.

 Let's dive right in by starting off with the proof-of-concept code:

Looking at this, we have a couple of things going on. In pure HTML, we have a form element, as well as a button element that is part of the form. There's also an onload event handler on the body element that stores a copy of the form's elements attribute before calling the button's remove method. Lastly, it triggers a delayed call to the trigger function, which performs reclamation of a freed buffer prior to triggering the re-use.

The remove call seems fairly clear -- it will remove the button, but there is more about buttons, or specifically HTMLButtonElements, that we need to know. It is important to understand the HTMLButtonElement class inherits from HTMLFormControlElement, which in turn inherits from FormAssociatedElement. All FormAssociatedElement instances have a potentially-NULL reference to an HTMLFormElement. When an instance is being destroyed, setForm is called with a NULL newForm argument. Within setForm, if the instance currently has an associated form, removeFormElement is called on the form with the instance as the sole argument. Doing this ensures that a form has no reference to an element that has been destroyed.

Clearly, there's more going on underneath the surface, so let's investigate the elements attribute on the form. If we look at the Interactive Data Language (IDL) file for HTMLFormElements in WebKit, we see this line describing the elements attribute:

Based on this information, we now know that the collection variable will end up storing an HTMLFormControlsCollection instance. If we look at how this is actually handled by the class, we see the following:

By accessing the elements attribute, a cached collection with HTMLFormControlsCollection as the container type will be created. This cached collection stores a reference to every element that was part of the form when the elements attribute is first accessed. However, references from the cached collection are not later removed if the elements are removed from the form. As a result, you can access freed objects.

This particular vulnerability was patched on November 3rd with git commit 8b2f1874e0727bb207e8e4625870763b3d75dc5e, which made a two-line change to the removeFormElement function. Now when an element is being disassociated from a form, the NodeList will have its cache invalidated, removing the leftover reference to the removed element.

Another interesting thing to note with this bug is that it was initially presented as part of a larger exploit chain targeting Wi-Fi on a fully patched iPhone 7. At the MP2O contest, the full exploit chain succeeded, but in the disclosure room, we discovered one of the bugs used was the same as a bug submitted in a previous attempt by a different competitor the day before. Since a successful Pwn2Own entry requires true 0day, the team was only awarded a partial success for the attempt.

As we approach this year’s Pwn2Own event, it will be interesting to see what research shows up, and how many people bring it. It’s always intriguing, and not just for the bugs. We hope to see you in Vancouver.

You can find me on Twitter at @WanderingGlitch, and follow the team for the latest in exploit techniques and security patches.