New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
link

Issue 888926: Security: UaF in Appcache

Reported by no...@beyondsecurity.com, Sep 25

Issue description

UserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36

Steps to reproduce the problem:
Run the python script, it requires multiple IP addresses for the successful exploitation, easiest way to recreate is by using localhost (as 127.0.0.1, 127.0.0.2, etc can be used)

What is the expected behavior?
The combined payload of the Chrome RCE (reported in another bug report sent a few minutes ago from me) with this SBX will cause a Calc to pop up.

The best way to see the bug is to have Google Chrome run as Guest account (rather than a logged in account), it increases the probability closer to 100%, without it, the probability of success is around 80%

What went wrong?
A bug in the appcache subsystem of the browser causes a UAF via a decrementing of the value allows to escape the Chrome SBX.

Did this work before? N/A 

Chrome version: 69.0.3497.100  Channel: stable
OS Version: 10.0
Flash Version: 

The following vulnerability acknowledgement is requested:
Two independent security researcher, Ned Williamson and Niklas Baumstark, have reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
 

Comment 1 by wfh@chromium.org, Sep 25

Cc: amuse@google.com

Comment 2 by wfh@chromium.org, Sep 25

Hi, thanks for your report. unfortunately we cannot decrypt the GPG attachment because it seems to be encrypted to the wrong key.

please feel free to re-encrypt with the security@google.com or security@chromium.org (we can handle either/both)

https://pgp.mit.edu/pks/lookup?op=get&search=0xB8E4105CC9DEDC77 (security@google.com)
https://pgp.mit.edu/pks/lookup?op=get&search=0xA73851D532C206B6 (security@chromium.org)

Comment 3 by mmoroz@chromium.org, Sep 25

Labels: -Pri-2 Pri-0

Comment 4 by mmoroz@chromium.org, Sep 25

Cc: mmoroz@chromium.org
Labels: M-69 Security_Severity-Critical Security_Impact-Stable

Comment 5 by wfh@chromium.org, Sep 25

Cc: nedwilli...@gmail.com pwnall@chromium.org jsb...@chromium.org
Components: Blink>Storage>AppCache
Ned has kindly offered to help with triage of this bug while we wait for the report to come through decrypted.

Comment 6 by no...@beyondsecurity.com, Sep 26

Attaching it in unencrypted form
chromesbx.zip
80.2 KB Download

Comment 7 by sheriffbot@chromium.org, Sep 26

Project Member
Labels: ReleaseBlock-Beta
This is a critical security issue. If you are not able to fix this quickly, please revert the change that introduced it.

If this doesn't affect a release branch, or has not been properly classified for severity, please update the Security_Impact or Security_Severity labels, and remove the ReleaseBlock label. To disable this altogether, apply ReleaseBlock-NA.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot

Comment 8 by mmoroz@chromium.org, Sep 26

Owner: jsb...@chromium.org
Status: Assigned (was: Unconfirmed)
jsbell@, could you please take a look or help to find an owner?

Comment 9 by mmoroz@chromium.org, Sep 26

Cc: -jsb...@chromium.org dcheng@chromium.org

Comment 10 by mmoroz@chromium.org, Sep 26

Labels: OS-Android OS-Chrome OS-Fuchsia OS-iOS OS-Linux OS-Mac
I suppose this affects all platforms.

Comment 11 by wfh@chromium.org, Sep 26

Summary: Security: UaF in Appcache (was: Security: Chrome SBX)
Here is the writeup from inside the ZIP. Please address this pri-0 critical bug as soon as possible.

Vulnerability:

The vulnerability exists in the AppCache subsystem in Chrome.
This code is located in the privileged browser process outside
of the sandbox. The renderer interacts with this subsystem by
sending IPC messages from the renderer to the browser process.
These messages can cause the browser to make network requests,
which are also attacker-controlled and influence the behavior
of the code.

See the following snippet from AppCacheGroup::RemoveCache:

```
void AppCacheGroup::RemoveCache(AppCache* cache) {
  DCHECK(cache->associated_hosts().empty());
  if (cache == newest_complete_cache_) {
    CancelUpdate(); // buggy call here
    AppCache* tmp_cache = newest_complete_cache_;
    newest_complete_cache_ = nullptr;
    tmp_cache->set_owning_group(nullptr);  // may cause this group to be deleted
  } else {
```

Notice the `AppCache* cache` paramter. This is a reference-counted
object, and this `RemoveCache` function can be called during the
`AppCache` destructor. The `CancelUpdate` can re-entrantly add a
reference to the AppCache that's passed in which is currently being
destroyed. When that pointer is later accessed, a use after free
occurs.

Here's how the reference count be incremented; recall newest_complete_cache_
has 0 references and is in the process of destruction.

`CancelUpdate` deletes an in progress `AppCacheUpdateJob`.

```
void AppCacheGroup::CancelUpdate() {
  if (update_job_) {
    delete update_job_;
    // The update_job_ destructor calls AppCacheGroup::SetUpdateAppCacheStatus
    // which zeroes update_job_.
    DCHECK(!update_job_);
    DCHECK_EQ(IDLE, update_status_);
  }
}
```

The AppCacheUpdateJob destructor calls `SetUpdateAppCacheStatus`.

```
AppCacheUpdateJob::~AppCacheUpdateJob() {
  if (service_)
    service_->RemoveObserver(this);
  if (internal_state_ != COMPLETED)
    Cancel();

  DCHECK(!inprogress_cache_.get());
  DCHECK(pending_master_entries_.empty());

  // The job must not outlive any of its fetchers.
  CHECK(!manifest_fetcher_);
  CHECK(pending_url_fetches_.empty());
  CHECK(master_entry_fetches_.empty());

  if (group_)
    group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE);
}
```

In `SetUpdateAppCacheStatus`, if the job was not idle, we call
`observer.OnUpdateComplete`, on every `AppCacheHost` currently
observing the `AppCacheGroup`.

```
void AppCacheGroup::SetUpdateAppCacheStatus(UpdateAppCacheStatus status) {
  if (status == update_status_)
    return;

  update_status_ = status;

  if (status != IDLE) {
    DCHECK(update_job_);
  } else {
    update_job_ = nullptr;

    // Observers may release us in these callbacks, so we protect against
    // deletion by adding an extra ref in this scope (but only if we're not
    // in our destructor).
    scoped_refptr<AppCacheGroup> protect(is_in_dtor_ ? nullptr : this);
    for (auto& observer : observers_)
      observer.OnUpdateComplete(this);
```

Now finally, recall that `newest_complete_cache_` is currently being
destroyed, but is not yet NULL. This means for as many hosts as we
add as observers for this AppCacheGroup we can add an arbitrary number
of references to the destroyed object.

```
void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) {
  DCHECK_EQ(group, group_being_updated_.get());
  group->RemoveUpdateObserver(this);

  // Add a reference to the newest complete cache.
  SetSwappableCache(group);
```

```
void AppCacheHost::SetSwappableCache(AppCacheGroup* group) {
  if (!group) {
    swappable_cache_ = nullptr;
  } else {
    AppCache* new_cache = group->newest_complete_cache();
    if (new_cache != associated_cache_.get())
      swappable_cache_ = new_cache;
```

Reproducing the Issue:

To reproduce the issue, apply the attached `renderer-271eaf.patch`,
build with ASAN, run the server located at `server/.py`, and browse
to `localhost:8000`. I believe this bug can be fixed by modifying
`AppCacheGroup::RemoveCache` to move the `CancelUpdate()` call to
after setting `newest_complete_cache_ = nullptr;`. This way the
invalid newest_complete_cache_ won't be accessed when setting a new
swappable cache.

Exploit Technique:

This bug provides us two essential primitives: use-after-free
decrement-by-N of the first dword of the freed object, where
N is controlled. If in the process of decrementing, the first
dword reaches 0, the AppCache destructor is called and the
pointer is freed.

We use these primitives in two stages: first, to construct a leak,
and second, to trigger code execution.

The freed AppCache object has size 0xA0 bytes. We found that
`net::CanonicalCookie` has the same size, so we can spray cookies
in the browser process by making a network request and including
cookies in the reseponse.

`std::string name` is the first object in the CanonicalCookie. This
name is the key from the key/value pair `name=value` from the cookie
string. On Windows STL, the first qword of a std::string object is a
pointer to the string data. By using decrement-by-N, we leak a number
of bytes by reading the cookie back from the browser and scanning the
`name` field. This leak gives us a heap address, which allows us to
spray the heap and predictably place controlled data at a now-known
address.

To achieve code execution, we produce a single dangling reference to
a freed AppCache via the described vulnerability. We reclaim it with
a blob of the same size, forging a reference count of 1 and a fake
AppCacheGroup with reference count 0. Once we remove the dangling
reference and enter the AppCache destructor, the else branch of the
RemoveCache method will cause the AppCacheGroup to be freed due to its
reference count going from 0 to 1 and back to 0.

```
void AppCacheGroup::RemoveCache(AppCache* cache) {
  DCHECK(cache->associated_hosts().empty());
  if (cache == newest_complete_cache_) {
    // ...
  } else {
    scoped_refptr<AppCacheGroup> protect(this);
    // ...
  }
}
```

The AppCacheGroup destructor in turn performs a virtual call, which
we fully control.

```
AppCacheGroup::~AppCacheGroup() {
  // ...
  if (update_job_)
    delete update_job_; // <- code execution here
}
```

Due to the once-per-boot ASLR approach of Windows, all modules are loaded
at the same address in the renderer and broker process. We use a gadget
from __longjmp_internal to bootstrap the ROP. From there we can either
jump to shellcode or open notepad.


Credit:
Ned Williamson (Bug, Exploit)
Niklas Baumstark (Exploit)

Comment 12 by kerrnel@google.com, Sep 26

Cc: kerrnel@chromium.org

Comment 13 by awhalley@google.com, Sep 26

Cc: awhalley@google.com

Comment 14 by kerrnel@google.com, Sep 26

Cc: nrpeter@google.com

Comment 15 by nedwilli...@gmail.com, Sep 26

I think this was missing from the writeup, but I think the bug was introduced here : https://chromium.googlesource.com/chromium/src/+/22e5bbdd259f9ca5393dfd32a6f8fc02f7c600a0

Moving the CancelUpdate call to after `newest_complete_cache_ = nullptr;` fixed the bug for me but I didn't check whether or not that introduces a regression.

Comment 16 by awhalley@google.com, Sep 26

Cc: chrome-owp-storage@google.com

Comment 17 by jsb...@chromium.org, Sep 26

Cc: mek@chromium.org

Comment 18 by jsb...@chromium.org, Sep 26

Cc: -mek@chromium.org jsb...@chromium.org
Owner: mek@chromium.org

Comment 19 by jsb...@chromium.org, Sep 26

Cc: cmumford@chromium.org

Comment 20 by bugdroid1@chromium.org, Sep 26

Project Member
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/9d2ead1650a1c901754dd1a68705006a6934cffc

commit 9d2ead1650a1c901754dd1a68705006a6934cffc
Author: Chris Palmer <palmer@chromium.org>
Date: Wed Sep 26 21:21:29 2018

Refcount AppCacheGroup correctly.

Bug:  888926 
Change-Id: Iab0d82d272e2f24a5e91180d64bc8e2aa8a8238d
Reviewed-on: https://chromium-review.googlesource.com/1246827
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Commit-Queue: Chris Palmer <palmer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#594475}
[modify] https://crrev.com/9d2ead1650a1c901754dd1a68705006a6934cffc/content/browser/appcache/appcache_group.cc

Comment 21 by wfh@chromium.org, Sep 28

Is this Fixed? Does it need a merge?

Comment 22 by mek@chromium.org, Sep 28

Labels: Merge-Request-69 Merge-Request-70
Status: Fixed (was: Assigned)
Oh sorry, yes and yes.

Comment 23 by sheriffbot@chromium.org, Sep 28

Project Member
Labels: -Merge-Request-70 Merge-Review-70 Hotlist-Merge-Review
This bug requires manual review: Less than 14 days to go before AppStore submit on M70
Please contact the milestone owner if you have questions.
Owners: benmason@(Android), kariahda@(iOS), geohsu@(ChromeOS), abdulsyed@(Desktop)

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot

Comment 24 by sheriffbot@chromium.org, Sep 28

Project Member
Labels: -Restrict-View-SecurityTeam Restrict-View-SecurityNotify

Comment 25 by awhalley@google.com, Sep 28

Cc: abdulsyed@chromium.org
abdulsyed@ - good for 70

Comment 26 by abdulsyed@chromium.org, Sep 28

Labels: -Merge-Review-70 Merge-Approved-70

Comment 27 by abdulsyed@chromium.org, Sep 28

Approving for M70. branch:3538

There are no respins planned for M69 yet.

Comment 28 by bugdroid1@chromium.org, Sep 28

Project Member
Labels: -merge-approved-70 merge-merged-3538
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/8b3539517f8a751cdba9f5276fb060a23b05053e

commit 8b3539517f8a751cdba9f5276fb060a23b05053e
Author: Marijn Kruisselbrink <mek@chromium.org>
Date: Fri Sep 28 16:49:07 2018

Refcount AppCacheGroup correctly.

TBR=palmer@chromium.org

(cherry picked from commit 9d2ead1650a1c901754dd1a68705006a6934cffc)

Bug:  888926 
Change-Id: Iab0d82d272e2f24a5e91180d64bc8e2aa8a8238d
Reviewed-on: https://chromium-review.googlesource.com/1246827
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Commit-Queue: Chris Palmer <palmer@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#594475}
Reviewed-on: https://chromium-review.googlesource.com/1252004
Cr-Commit-Position: refs/branch-heads/3538@{#733}
Cr-Branched-From: 79f7c91a2b2a2932cd447fa6f865cb6662fa8fa6-refs/heads/master@{#587811}
[modify] https://crrev.com/8b3539517f8a751cdba9f5276fb060a23b05053e/content/browser/appcache/appcache_group.cc

Comment 29 by cr-audit...@appspot.gserviceaccount.com, Sep 28

Project Member
Labels: Merge-Merged-70-3538
The following revision refers to this bug: 
https://chromium.googlesource.com/chromium/src.git/+/8b3539517f8a751cdba9f5276fb060a23b05053e

Commit: 8b3539517f8a751cdba9f5276fb060a23b05053e
Author: mek@chromium.org
Commiter: mek@chromium.org
Date: 2018-09-28 16:49:07 +0000 UTC

Refcount AppCacheGroup correctly.

TBR=palmer@chromium.org

(cherry picked from commit 9d2ead1650a1c901754dd1a68705006a6934cffc)

Bug:  888926 
Change-Id: Iab0d82d272e2f24a5e91180d64bc8e2aa8a8238d
Reviewed-on: https://chromium-review.googlesource.com/1246827
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Commit-Queue: Chris Palmer <palmer@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#594475}
Reviewed-on: https://chromium-review.googlesource.com/1252004
Cr-Commit-Position: refs/branch-heads/3538@{#733}
Cr-Branched-From: 79f7c91a2b2a2932cd447fa6f865cb6662fa8fa6-refs/heads/master@{#587811}

Comment 30 by awhalley@google.com, Sep 29

Labels: M-70

Comment 31 by awhalley@chromium.org, Oct 1

Labels: reward-topanel

Comment 32 by awhalley@google.com, Oct 3

Labels: -ReleaseBlock-Beta

Comment 33 by awhalley@google.com, Oct 3

Labels: -Security_Severity-Critical Security_Severity-High

Comment 34 by awhalley@google.com, Oct 4

Labels: -reward-topanel reward-0

Comment 35 by gov...@chromium.org, Oct 8

Labels: -Merge-Request-69 Merge-Rejected-69
We're not planning any further M69 releases, Rejecting merge to M69.

Comment 36 by awhalley@chromium.org, Oct 9

Cc: manjian2...@gmail.com
(CCing Chromium embedder)

Comment 37 by infe...@chromium.org, Oct 10

Cc: kcc@chromium.org

Comment 38 by awhalley@google.com, Oct 15

Labels: Release-0-M70

Comment 39 by awhalley@chromium.org, Oct 16

Labels: CVE-2018-17462 CVE_description-missing

Comment 40 by infe...@chromium.org, Oct 29

Cc: rising@google.com

Comment 41 by mmoroz@chromium.org, Oct 30

Cc: dvyukov@google.com

Comment 42 by bugdroid1@chromium.org, Nov 6

Project Member

Comment 43 by awhalley@chromium.org, Nov 12

Labels: -CVE_description-missing CVE_description-submitted

Comment 44 by wfh@chromium.org, Nov 21

Cc: shuntley@google.com

Comment 45 by shuntley@google.com, Nov 21

Cc: nmehta@google.com

Comment 46 by sheriffbot@chromium.org, Jan 4

Project Member
Labels: -Restrict-View-SecurityNotify allpublic
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot

Sign in to add a comment