Thursday, October 4, 2018

365 Days Later: Finding and Exploiting Safari Bugs using Publicly Available Tools

Posted by Ivan Fratric, Google Project Zero

Around a year ago, we published cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results of research about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resilience of modern browsers against DOM fuzzing, a well-known technique for finding browser bugs. Togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug statistics we also published Domato, our DOM fuzzing tool that was used to find those bugs.

Given that in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous research, Apple Safari, or more specifically, WebKit (its DOM engine) did noticeably worse than ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r browsers, we decided to revisit it after a year using exactly cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same methodology and exactly cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same tools to see whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r anything changed.

Test Setup

As in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original research, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzing was initially done against WebKitGTK+ and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crashes were tested against Apple Safari running on a Mac. This makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzing setup easier as WebKitGTK+ uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same DOM engine as Safari, but allows for fuzzing on a regular Linux machine. In this research, WebKitGTK+ version 2.20.2 was used which can be downloaded here.

To improve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzing process, a couple of custom changes were made to WebKitGTK+:

  • Made fixes to be able to build WebKitGTK+ with ASan (Address Sanitizer).

  • Changed window.alert() implementation to immediately call cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 garbage collector instead of displaying a message window. This works well because window.alert() is not something we would normally call during fuzzing.

  • Normally, when a DOM bug causes a crash, due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 multi-process nature of WebKit, only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 web process would crash, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main process would continue running. Code was added that monitors a web process and, if it crashes, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code would “crash” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main process with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same status.

  • Created a custom target binary.

After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous research was published, we got a lot of questions about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 details of our fuzzing setup. This is why, this time, we are publishing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 changes made to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKitGTK+ code as well as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 detailed build instructions below. A patch file can be found here. Note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch was made with WebKitGTK+ 2.20.2 and might not work as is on ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r versions.

Once WebKitGTK+ code was prepared, it was built with ASan by running cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following commands from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKitGTK+ directory:

export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
export CFLAGS="-fsanitize=address"
export CXXFLAGS="-fsanitize=address"
export LDFLAGS="-fsanitize=address"
export ASAN_OPTIONS="detect_leaks=0"

mkdir build
cd build

cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=. -DCMAKE_SKIP_RPATH=ON -DPORT=GTK -DLIB_INSTALL_DIR=./lib -DUSE_LIBHYPHEN=OFF -DENABLE_MINIBROWSER=ON -DUSE_SYSTEM_MALLOC=ON -DENABLE_GEOLOCATION=OFF -DENABLE_GTKDOC=OFF -DENABLE_INTROSPECTION=OFF -DENABLE_OPENGL=OFF -DENABLE_ACCELERATED_2D_CANVAS=OFF -DENABLE_CREDENTIAL_STORAGE=OFF -DENABLE_GAMEPAD_DEPRECATED=OFF -DENABLE_MEDIA_STREAM=OFF -DENABLE_WEB_RTC=OFF -DENABLE_PLUGIN_PROCESS_GTK2=OFF -DENABLE_SPELLCHECK=OFF -DENABLE_VIDEO=OFF -DENABLE_WEB_AUDIO=OFF -DUSE_LIBNOTIFY=OFF -DENABLE_SUBTLE_CRYPTO=OFF -DUSE_WOFF2=OFF -Wno-dev ..

make -j 4

mkdir -p libexec/webkit2gtk-4.0
cp bin/WebKit*Process libexec/webkit2gtk-4.0/

If you are doing this for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first time, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cmake/make step will likely complain about missing dependencies, which you will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n have to install. You might note that a lot of features deemed not overly important for DOM fuzzing were disabled via -DENABLE flags. This was mainly to save us from having to install cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding dependencies but in some cases also to create a build that was more “portable”.

After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 build completes, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzing is as simple as creating a sample with Domato, running cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target binary as

ASAN_OPTIONS=detect_leaks=0,exitcode=42 ASAN_SYMBOLIZER_PATH=/path/to/llvm-symbolizer LD_LIBRARY_PATH=./lib ./bin/webkitfuzz /path/to/sample

and waiting for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exit code 42 (which, if you take a look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command line above as well as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 changes we made to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKitGTK+ code, indicates an ASan crash).

After collecting crashes, an ASan build of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most recent WebKit source code was created on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual Mac hardware. This is as simple as running

./Tools/Scripts/set-webkit-configuration --release --asan
./Tools/Scripts/build-webkit

Each crash obtained on WebKitGTK+ was tested against cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mac build before reporting to Apple.

The Results

After running cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzer for 100.000.000 iterations (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as a year ago) I ended up with 9 unique bugs that were reported to Apple. Last year, I estimated that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 computational power to perform this number of iterations could be purchased for about $1000 and this probably hasn’t changed - an amount well within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payment range of a wide range of attackers with varying motivation.

The bugs are summarized in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 table below. Please note that all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs have been fixed at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time of release of this blog post.

Project Zero bug ID
CVE
Type
Affected Safari 11.1.2
Older than 6 months
Older than 1 year
CVE-2018-4197
UAF
YES
YES
NO
CVE-2018-4318
UAF
NO
NO
NO
CVE-2018-4317
UAF
NO
YES
NO
CVE-2018-4314
UAF
YES
YES
NO
CVE-2018-4306
UAF
YES
YES
NO
CVE-2018-4312
UAF
NO
NO
NO
CVE-2018-4315
UAF
YES
YES
NO
CVE-2018-4323
UAF
YES
YES
NO
CVE-2018-4328
OOB read
YES
YES
YES
UAF = use-after-free. OOB = out-of-bounds

As can be seen in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 table, out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 9 bugs found, 6 affected cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 release version of Apple Safari, directly affecting Safari users.

While 9 or 6 bugs (depending how you count) is significantly less than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 17 found a year ago, it is still a respectable number of bugs, especially if we take into an account that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzer has been public for a long time now.

After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results were in, I looked into how long cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se bugs have been in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKit codebase. To check this, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs were tested against a version of WebKitGTK+ that was more than 6 months old (WebKitGTK+ 2.19.6) as well as a version that was more than a year old (WebKitGTK+ 2.16.6).

The results are interesting—most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs were sitting in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKit codebase for longer than 6 months, however, only 1 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m is older than 1 year. Here, it might be important to note that throughout cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past year (between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous and this blog post) I also did fuzzing runs using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same approach and reported 14 bugs. Unfortunately, it is impossible to know how many of those 14 bugs would have survived until now and how many would have been found in this fuzz run. It is also possible that some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 newly found bugs are actually older, but don’t trigger with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 provided PoCs is in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 older versions due to unrelated code changes in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DOM. I didn’t investigate this possibility.

However, even if we assume that all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previously reported bugs would not have survived until now, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results still indicate that (a) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security vulnerabilities keep getting introduced in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WebKit codebase and (b) many of those bugs get incorporated into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 release products before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are caught by internal security efforts.

While (a) is not unusual for any piece of software that changes as rapidly as a DOM engine, (b) might indicate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 need to put more computational resources into fuzzing and/or review before release.

The Exploit

To prove that bugs like this can indeed lead to a browser compromise, I decided to write an exploit for one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. The goal was not to write a very reliable or sophisticated exploit - highly advanced attackers would likely not choose to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs found by public tools whose lifetime is expected to be relatively short. However, if someone with exploit writing skills was to use such a bug in, for example, a malware spreading campaign, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y could potentially do a lot of damage even with an unreliable exploit.

Out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 6 issues affecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 release version of Safari, I selected what I believed to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 easiest one to exploit—a use-after-free where, unlike in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r use-after-free issues found, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object is not on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 isolated heap—a mitigation recently introduced in WebKit to make use-after-free exploitation harder.

Let us first start by examining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug we’re going to exploit. The issue is a use-after-free in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVGAnimateElementBase::resetAnimatedType() function. If you look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function, you are going to see that, first, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function gets a raw pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVGAnimatedTypeAnimator object on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 line

   SVGAnimatedTypeAnimator* animator = ensureAnimator();

and, towards cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator object is used to obtain a pointer to a SVGAnimatedType object (unless one already exists) on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 line

   m_animatedType = animator->constructFromString(baseValue);

The problem is that, in between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two lines, attacker-controlled JavaScript code could run. Specifically, this could happen during a call to computeCSSPropertyValue(). The JavaScript code could cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cause SVGAnimateElementBase::resetAnimatedPropertyType() to be called, which would delete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator object. Thus, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constructFromString() function would be called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed animator object - a typical use-after-free scenario, at least on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first glance. There is a bit more to this bug though, but we’ll get to that later.

The vulnerability has been fixed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latest Safari by no longer triggering JavaScript callbacks through computeCSSPropertyValue(). Instead, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event handler is going to be processed at some later time. The patch can be seen here.

A simple proof of concept for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is:

 
   
 
 
   
 
 

Here, svg.setCurrentTime() results in resetAnimatedType() being called, which in turn, due to DOM mutations made previously, causes a JavaScript event handler to be called. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event handler, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator object is deleted by resetting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attributeName attribute of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animate element.

Since constructFromString() is a virtual method of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVGAnimatedType class, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitive cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability gives us is a virtual method call on a freed object.

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 days before ASLR, such a vulnerability would be immediately exploitable by replacing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object with data we control and faking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual method table of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object, so that when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual method is called, execution is redirected to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker’s ROP chain. But due to ASLR we won’t know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 addresses of any executable modules in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process.

A classic way to overcome this is to combine such a use-after-free bug with an infoleak bug that can leak an address of one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable modules. But, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a problem: In our crop of bugs, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re wasn’t a good infoleak we could use for this purpose. A less masochistic vulnerability researcher would simply continue to run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fuzzer until a good infoleak bug would pop up. However, instead of finding better bugs, I deliberately wanted to limit myself to just cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs found in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same number of iterations as in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous research. As a consequence, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 majority of time spent working on this exploit was to turn cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug into an infoleak.

As stated before, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitive we have is a virtual method call on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object. Without an ASLR bypass, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only thing we can do with it that would not cause an immediate crash is to replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object with anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r object that also has a vtable, so that when a virtual method is called, it is called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r object. Most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time, this would mean calling a valid virtual method on a valid object and nothing interesting would happen. However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are several scenarios where doing this could lead to interesting results:

  1. The virtual method could be something dangerous to call out-of-context. For example, if we can call a destructor of some object, its members could get freed while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object itself continues to live. With this, we could turn cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original use-after-free issue into anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r use-after-free issue, but possibly one that gives us a better exploitation primitive.

  1. Since constructFromString() takes a single parameter of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type String, we could potentially cause a type confusion on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input parameter if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r virtual method expects a parameter of anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r type. Additionally, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r virtual method takes more parameters than constructFromString(), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se would be uninitialized which could also lead to exploitable behavior.

  1. As constructFromString() is expected to return a pointer of type SVGAnimatedType, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r virtual method returns some ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r type, this will lead to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confusion on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 return value. Additionally, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r virtual method does not return anything, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 return value remains uninitialized.

  1. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtables of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object we replaced it with are of different size, calling a vtable pointer on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object could result in an out-of-bounds read on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r object, resulting in calling a virtual function of some third class.

In this exploit we used option 3, but with a twist. To understand what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 twist is, let’s examine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVGAnimateElementBase class more closely: It implements (most of) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 functionality of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVG element. The SVG element is used to, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name suggests, animate a property of anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r element. For example, having cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following element in an SVG image


will cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 x coordinate of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target element (by default, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parent element) to grow from 0 to 100 over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 duration of 10 seconds. We can use an element to animate various CSS or XML properties, which is controlled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attributeName property of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 element.

Here’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interesting part: These properties can have different types. For example, we might use an element to animate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 x coordinate of an element, which is of type SVGLengthValue (number + unit), or we might use it to animate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fill attribute, which is of type Color.

In an SVGAnimateElementBase class, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of animated property is tracked via a member variable declared as

   AnimatedPropertyType m_animatedPropertyType;

Where AnimatedPropertyType is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 enumeration of possible types. Two ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r member variables of note are

   std::unique_ptr m_animator;
   std::unique_ptr m_animatedType;

The m_animator here is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free object, while m_animatedType is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object created from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 (possibly freed) m_animator.

SVGAnimatedTypeAnimator (type of m_animator) is a superclass which has subclasses for all possible values of AnimatedPropertyType, such as SVGAnimatedBooleanAnimator, SVGAnimatedColorAnimator etc. SVGAnimatedType (type of m_animatedType) is a variant that contains a type and a union of possible values depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type.

The important thing to note is that normally, both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subclass of m_animator and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of m_animatedType are supposed to match m_animatedPropertyType. For example, if m_animatedPropertyType is AnimatedBoolean, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of m_animatedType variant should be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same, and m_animator should be an instance of SVGAnimatedBooleanAnimator.

After all, why shouldn’t all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types match, since m_animator is created based on m_animatedPropertyType here and m_animatedType is created by m_animator here. Oh wait, that’s exactly where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability occurs!

So instead of replacing a freed animator with something completely different and causing a type confusion between SVGAnimatedType and anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r class, we can instead replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed animator with anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r animator subclass and confuse SVGAnimatedType with type = A to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r SVGAnimatedType with type = B.

But one interesting thing about this bug is that it would still be a bug even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator object did not get freed. In that case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug turns into a type confusion: To trigger it, one would simply change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 m_animatedPropertyType of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 element to a different type in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JavaScript callback (we’ll examine how this happens in detail later). This led to some discussion in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 office whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug should be called an use-after-free at all, or is this really a different type of bug where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free is merely a symptom.

Note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator object is always going to get freed as soon as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 element changes, which leads to an interesting scenario where to exploit a bug (however you choose to call it), instead of replacing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object with an object of anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r type, we could eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r replace it with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same type or make sure it doesn’t get replaced at all. Due to how memory allocation in WebKit works, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latter is actually going to happen on its own most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time anyway - objects allocated in a memory page will only start getting replaced once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole page becomes full. Additionally, freeing an object in WebKit doesn’t corrupt it as would be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case in some ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r allocators, which allows us to still use it normally even after being freed.

Let’s now examine how this type confusion works and what effects it has:

  1. We start with an element for type A. m_animatedPropertyType, m_animator and m_animatedType all match type A.

  1. resetAnimatedType() gets called and it retrieves an animator pointer of type A here.

  1. resetAnimatedType() calls computeCSSPropertyValue() here, which triggers a JavaScript callback.

  1. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JavaScript callback, we change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of element to B by changing its attributeName attribute. This causes SVGAnimateElementBase::resetAnimatedPropertyType() to be called. In it, m_animatedType and m_animator get deleted, while m_animatedPropertyType gets set to B according to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new attributeName here. Now, m_animatedType and m_animator are null, while m_animatedPropertyType is B.

  1. We return into resetAnimatedType(), where we still have a local variable animator which still points to (freed but still functional) animator for type A.

  1. m_animatedType gets created based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed animator here. Now, m_animatedType is of type A, m_animatedPropertyType is B and m_animator is null.

  1. resetAnimatedType() returns, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator local variable pointing to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed animator of type A gets lost, never to be seen again.

  1. Eventually, resetAnimatedType() gets called again. Since m_animator is still null, but m_animatedPropertyType is B, it creates m_animator of type B here.

  1. Since m_animatedType is non-null, instead of creating it anew, we just initialize it by calling m_animatedType->setValueAsString() here. We now have m_animatedPropertyType for type B, m_animator for type B and m_animatedType for type A.

  1. At some point, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animated property gets calculated. That happens in SVGAnimateElementBase::calculateAnimatedValue() on this line by calling m_animator->calculateAnimatedValue(..., m_animatedType). Here, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a mismatch between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 m_animator (type B) and  m_animatedType (type A). However, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mismatch wouldn’t normally occur, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animator won’t check cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 argument (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re might be some debug asserts but nothing in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 release) and will attempt to write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 calculated animated value of type B into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVGAnimatedType with type A.

  1. After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 animated value has been computed, it is read out as string and set to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding CSS property. This happens here.

The actual type confusion only happens in step 10: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re, we will write to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SVGAnimatedType of type A as if it actually was type B. The rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interactions with m_animatedType are not dangerous since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are simply getting and setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value as string, an operation that is safe to do regardless of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual type.

Note that, although cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 element supports animating XML properties as well as CSS properties, we can only do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above dance with CSS properties as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code for handling XML properties is different. The list of CSS properties we can work with can be found here.

So, how do we exploit this type confusion for an infoleak? The initial idea was to exploit with A = and B = String. This way, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confusion on write occurs, a string pointer is written over a number and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n we would be able to read it in step 11 above. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a problem with this (as well as with a large number of type combinations): The value read in step 11 must be a valid CSS property value in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current animated property, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise it won’t be set correctly and we would not be able to read it out. For example, we were unable to find a string CSS property (from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list above) that would accept a value like 1.4e-45 or similar.

A more promising approach, due to limitations of step 11, would be to replace a numeric type with anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r numeric type. We had some success with A = FloatRect and B = SVGLengthListValues, which is a vector of SVGLengthValue values. Like above, this results in a vector pointer being written over FloatRect type. This sometimes leads to successfully disclosing a heap address. Why sometimes? Because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only CSS property with type SVGLengthListValues we can use is stroke-dasharray, and stroke-dasharray accepts only positive values. Thus, if lower 32-bits of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap address we want to disclose look like a negative floating point number (i.e. cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 highest bit is set), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n we would not be able to disclose that address. This problem can be overcome by spraying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap with 2GB of data so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lower 32-bits of heap addresses start becoming positive. But, since we need heap spraying anyway, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r approach we can take.

The approach we actually ended up using is with A = SVGLengthListValues (stroke-dasharray CSS property) and B = float (stroke-miterlimit CSS property). What this type confusion does, is overwrites cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lowest 32 bits of a SVGLengthValue vector with a floating point number.

Before we trigger this type confusion we need to spray cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap with approximately 4GB of data (doable on modern computers), which gives us a good probability that when we change an original heap address 0x000000XXXXXXXXXX to 0x000000XXYYYYYYYY, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting address is still going to be a valid heap address, especially if YYYYYYYY is high. This way, we can disclose not-quite-arbitrary data at 0x000000XX00000000 + arbitrary offset.

Why not-quite-arbitrary? Because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are still some limitations:

  1. As stroke-miterlimit must be positive, once again we can only disclose data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap interpretable as a 32-bit float.

  1. SVGLengthValue is a type which consists of a 32-bit float followed by an enumeration that describes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 units used. When a SVGLengthValue is read out as string in step 11 above, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unit value is valid, it will be appended to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number (e.g. ‘100px’). If we attempt to set a string like that to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stroke-miterlimit property it will fail. Thus, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next byte after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap value we want to read must interpret as invalid unit (in which case cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unit is not appended when reading out SVGLengthValue as string).

Note that both of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se limitations can often be worked around by doing non-aligned reads.

Now that we have our more-or-less usable read, what do we read out? As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 whole point is to defeat ASLR, we should read a pointer to an executable module. Often in exploitation, one would do that by reading out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable pointer of some object on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap. However, on MacOS it appears that vtable pointers point to a separate memory region than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one containing executable code of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding module. So instead of reading out a vtable pointer, we need to read a function pointer instead.

What we ended up doing is using VTTRegion objects in our heap spray. A VTTRegion object contains a Timer which contains a pointer to Function object which (in this case) contains a function pointer to VTTRegion::scrollTimerFired(). Thus, we can spray with VTTRegion objects (which takes about 10 seconds on a quite not-state-of-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-art Mac Mini) and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n scan cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting memory for a function pointer.

This gives us cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ASLR bypass, but one ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r thing useful to have for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next phase is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payload (ROP chain and shellcode). We disclose it by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following steps:

  1. Find a VTTRegion object in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap spray.

  1. By setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 VTTRegion.height property during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap spray to an index in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 spray array, we can identify exactly which of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 millions of VTTRegion objects we just read.

  1. Set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 VTTRegion.id property of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 VTTRegion object to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payload.

  1. Read out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 VTTRegion.id pointer.

We are now ready for triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability a second time, this time for code exec. This time, it is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 classic use-after-free exploitation scenario: we overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed SVGAnimatedTypeAnimator object with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data we control.

As Apple recently introduced gigacage (a separate large region of memory) for a lot of attacker-controlled datatypes (strings, arrays, etc.) this is no longer trivial. However, one thing still allocated on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main heap is Vector content. By finding a vector whose content we fully control, we can overcome cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap limitations.

What I ended up using is a temporary vector used when TypedArray.set() is called to copy values from one JavaScript typed array into anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r typed array. This vector is temporary, meaning it will be deleted immediately after use, but again, due to how memory allocation works in webkit it is not too horrible. Like ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r stability improvements, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task of finding a more permanent controllable allocation is left to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exercise of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reader. :-)

This time, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 JavaScript event handler, we can replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed SVGAnimatedTypeAnimator with a vector whose first 8 bytes are set to point to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP chain + shellcode payload.

The ROP chain is pretty straightforward, but one thing that is perhaps more interesting is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pivot gadget (or, in this case, gadgets) used. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scenario we have, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual function on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object is called as

call qword ptr [rax+10h]

where rax points to our payload. Additionally, rsi points to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 freed object (that we now also control). The first thing we want to do for ROP is control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack, but I was unable to find any “classic” gadgets that accomplish this such as

mov rsp, rax; ret;
push rax; pop rsp; ret;
xchg rax, rsp; ret;

What I ended up doing is breaking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pivot into two gadgets:

push rax; mov rax, [rsi], call [rax + offset];

This first gadget pushes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 payload address on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack and is very common because, after all, that’s exactly how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original virtual function was called (apart from push rax that can be an epilogue of some ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r instruction). The second gadget can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be

pop whatever; pop rsp; ret;

where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first pop pops cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 return address from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second pop finally gets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 controlled value into rsp. This gadget is less common, but still appears to be way more common than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pivot mentioned previously, at least in our binary.

The final ROP chain is (remember to start reading from offset 0x10):

[address of pop; pop; pop; ret]
0
[address of push rax; mov rax, [rsi], call [rax+0x28]];
0
[address of pop; ret]
[address of pop rbp; pop rsp; ret;]
[address of pop rdi; ret]
0
[address of pop rsi; ret]
shellcode length
[address of pop rdx; ret]
PROT_EXEC + PROT_READ + PROT_WRITE
[address of pop rcx; ret]
MAP_ANON + MAP_PRIVATE
[address of pop r8; pop rbp; ret]
-1
0
[address of pop r9; ret]
0
[address of mmap]
[address of push rax; pop rdi; ret]
[address of push rsp; pop rbp; ret]
[address of push rbp; pop rax; ret]
[address of add rax, 0x50; pop rbp; ret]
0
[address of push rax; pop rsi; pop rbp; ret]
0
[address of pop rdx; ret]
shellcode length
[address of memcpy]
[address of jmp rax;]
0
shellcode

The ROP chain calls

mmap(0, shellcode_length,  PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANON + MAP_PRIVATE, -1, 0)

Then calculates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shellcode address and copies it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address returned by mmap(), after which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shellcode is called.

In our case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shellcode is just a sequence of ‘int 3’ instructions and when reaching it, Safari
will crash. If a debugger is attached, we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shellcode was successfully reached as it will detect a breakpoint:

Process 5833 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
   frame #0: 0x00000001b1b83001
->  0x1b1b83001: int3   
   0x1b1b83002: int3   
   0x1b1b83003: int3   
   0x1b1b83004: int3   
Target 0: (com.apple.WebKit.WebContent) stopped.

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 real-world scenario cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shellcode could eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r be a second-stage exploit to break out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Safari sandbox or, alternately, a payload that would turn cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue into an universal XSS, stealing cross-domain data.

The exploit was successfully tested on Mac OS 10.13.6 (build version 17G65). If you are still using this version, you might want to update. The full exploit can be seen here.

The impact of recent iOS mitigations

An interesting aspect of this exploit is that, on Safari for Mac OS it could be written in a very “old-school” way (infoleak + ROP) due to lack of control flow mitigations on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 platform.

On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latest mobile hardware and in iOS 12, which was published after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit was already written, Apple introduced control flow mitigations by using Pointer Aucá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ntication Codes (PAC). While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are no plans to write anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit at this time, it is interesting to discuss how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit could be modified not to be affected by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 recent mitigations.

The exploit, as presented here, consists of two parts: infoleak and getting code execution. PAC would not affect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 infoleak part in any way, however it would prevent jumping to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP chain in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, because we could not forge a correct signature for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable pointer.

Instead of jumping to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP code, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next stage of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit would likely need to be getting an arbitrary read-write primitive. This could potentially be accomplished by exploiting a similar type confusion that was used for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 infoleak, but with a different object combination. I did notice that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are some type combinations that could result in a write (especially if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker already has an infoleak), but I didn’t investigate those in detail.

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Webkit process, after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker has an arbitrary read-write primitive, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y could find a way to overwrite JIT code (or, failing that, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r data that would cause fully or partially controlled JIT code to be emitted) and achieve code execution that way.

So while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit could still be written, admittedly it would be somewhat more difficult to write.

On publishing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 advisories

Before concluding this blog post, we want to draw some attention to how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patches for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues listed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 blog post were announced and to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding timeline. The issues were reported to Apple between June 15 and July 2nd, 2018. On September 17th 2018, Apple published security advisories for iOS 12, tvOS 12 and Safari 12 which fixed all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues. However, although cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bugs were fixed at that time, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding advisories did not initially mention cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. The issues described in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 blog post were only added to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 advisories one week later, on September 24, 2018, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security advisories for macOS Mojave 10.14 were also published.

To demonstrate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 discrepancy between originally published advisories and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 updated advisories, compare cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 archived version of Safari 12 advisories from September 18 here and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same advisories here (note that you might need to refresh cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page if you still have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old version in your browser’s cache).

The original advisories most likely didn’t include all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues because Apple wanted to wait for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues to also be fixed on MacOS before adding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. However, this practice is misleading because customers interested in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Apple security advisories would most likely read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m only once, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are first released and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impression cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y would to get is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 product updates fix far less vulnerabilities and less severe vulnerabilities than is actually cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case.

Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 practice of not publishing fixes for mobile or desktop operating systems at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same time can put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 desktop customers at unnecessary risk, because attackers could reverse-engineer cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patches from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mobile updates and develop exploits against desktop products, while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 desktop customers would have no way to update and protect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves.

Conclusion

While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re were clearly improvements in WebKit DOM when tested with Domato, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 now public fuzzer was still able to find a large number of interesting bugs in a non-overly-prohibitive number of iterations. And if a public tool was able to find that many bugs, it is expected that private ones might be even more successful.

And while it is easy to brush away such bugs as something we haven’t seen actual attackers use, that doesn’t mean it’s not happening or that it couldn’t happen, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 provided exploit demonstrates. The exploit doesn’t include a sandbox escape so it can’t be considered a full chain, however reports from ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r security researchers indicate that this ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r aspect of browser security, too, cracks under fuzzing (Note from Apple Security: this sandbox escape relies on attacking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WindowServer, access to which has been removed from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandbox in Safari 12 on macOS Mojave 10.14). Additionally, a DOM exploit could be used to steal cross-domain data such as cookies even without a sandbox escape.

The fuzzing results might indicate that WebKit is getting fuzzed, but perhaps not with sufficient computing power to find all fuzzable, newly introduced bugs before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y make it into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 release version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser. We are hoping that this research will lead to improved user security by providing an incentive for Apple to allocate more resources into this area of browser security.
No comments:
Newer Posts Older Posts Home